<style lang="stylus" scoped>
  .icon-editor
    display flex
    background #2f2f37
    border 1px solid #1c1c21
    border-radius 4px
  .dropdown-button
    display flex
    align-items center
    width 90px
    line-height 38px
    text-align center
    font-size 12px
    color #565d6c
    transition .1s
    span
      width 50px
      flex-grow 1
      text-align center
    &:hover
      background #181b20
      color #c1c5cd
    &:active,
    &.active
      background #16181d
  .v-input
    width 20px
    flex-grow 1
    :deep(input)
      border-color transparent
  .mdi-help
    display flex
    width 40px
    align-items center
    justify-content center
    cursor pointer
    color #727e97
    transition .15s
    svg
      width 20px
      height 20px
    &:hover
      background #181b20
    &:active,
    &.active
      background #16181d
  .crab-message
    width 10px
    flex-grow 1
    padding-left 15px
    line-height 38px
    font-size 12px
    color #666
  </style>
  
  <template>
    <div class="icon-editor">
      <v-dropdown :arrow="true">
        <span>{{ iconTypeLabel }}</span>
        <template #body>
          <v-dropdown-item
            v-for="iconTypeItem in iconTypeConfigList"
            :key="iconTypeItem.name"
            :active="iconType === iconTypeItem.name"
            @click="iconType = iconTypeItem.name"
          >
            {{ iconTypeItem.label }}
          </v-dropdown-item>
        </template>
      </v-dropdown>
      <v-input
        v-if="iconType !== 'crab'"
        v-model="inputValue"
        :maxlength="iconType === 'mdi' ? 30 : 6"
        type="text"
      />
      <div
        v-else
        class="crab-message"
      >
        将尝试自动抓取图标
      </div>
      <div
        v-if="iconType === 'mdi'"
        class="mdi-help"
        @click="openMdiHelp"
      >
        <v-mdi name="mdi-help" />
      </div>
    </div>
  </template>
  
  <script lang="ts">
  import { ref, watch, PropType } from 'vue'
  import { BookmarkIcon } from '@/database/entity/bookmark'
  
  const iconTypeConfigList = [
    {
      name: 'text',
      label: '文字图标',
      default: '好看',
    },
    {
      name: 'mdi',
      label: 'mdi图标',
      default: 'mdi-heart-pulse',
    },
    {
      name: 'crab',
      label: '抓取图标',
      default: '',
    },
  ]
  // 根据 iconType 获取对应配置
  function getIconTypeConfig (iconType: string) {
    for(let i = 0; i < iconTypeConfigList.length; i++) {
      if (iconTypeConfigList[i].name === iconType) {
        return iconTypeConfigList[i]
      }
    }
    return iconTypeConfigList[0]
  }
  
  /**
   * 从图标数据，获取图标类型，用户输入值
   *   mdi:play   ->  ['mdi', 'mdi-play']
   *   text:play  ->  ['text', 'play']
   *   crab       ->  ['crab', '']
   */
  function decodeModelValue(iconConfig: BookmarkIcon) {
    const iconSplit = (iconConfig || '').split(':')
    if (iconSplit[0] === 'mdi') {
      return ['mdi', 'mdi-' + iconSplit[1]]
    } else if (iconConfig === 'crab') {
      return ['crab', '']
    }
    return ['text', iconSplit[1]]
  }
  
  /**
   * 从图标类型、用户输入值，生成图标数据
   *   ['mdi', 'mdi-play']  ->  mdi:play
   *   ['text', 'play']     ->  text:play
   *   ['crab', '']         ->  crab
   */
  function encodeModelValue(newIconType: string, inputValue: string): BookmarkIcon {
    if (newIconType === 'mdi') {
      const iconName = (inputValue || '').replace(/^mdi-/, '')
      // 经历过 replace 前后，值若不相等，则认为是合法的 mdi 配置
      if (inputValue !== iconName) {
        return `mdi:${iconName}`
      } else {
        // 否则，更正数据
        return 'mdi:'
      }
    } else if (newIconType === 'crab') {
      return 'crab'
    }
    return `text:${inputValue || ''}`
  }
  
  export default {
    props: {
      modelValue: {
        type: String as PropType<BookmarkIcon>,
        default: 'text: ',
      },
    },
    emits: ['update:modelValue'],
    setup(props: {
      modelValue: BookmarkIcon
    }, context) {
      const iconType = ref('')
      const inputValue = ref('')
      const iconTypeLabel = ref('')
  
      // 从应用图标数据，更新编辑器视图
      function applyBookmarkIcon(bookmarkIcon: BookmarkIcon) {
        // 从图标数据，获取图标类型，用户输入值
        const [ newIconType, newInputValue ] = decodeModelValue(bookmarkIcon)
        // 当图标类型和用户输入值相同时，不处理
        if (newIconType === iconType.value && newInputValue === inputValue.value) {
          return
        }
        // 更新数据
        iconType.value = newIconType
        inputValue.value = newInputValue
        iconTypeLabel.value = getIconTypeConfig(newIconType).label
      }
      // 监听用户交互操作行为
      function watchUserIntractive() {
        // 监听图标类型变化
        const unWatchIconType = watch(iconType, newIconType => {
          // 获取默认填充值
          let defaultInputValue = getIconTypeConfig(newIconType).default
          let newModelValue = encodeModelValue(newIconType, defaultInputValue)
          applyBookmarkIcon(newModelValue)
          context.emit('update:modelValue', newModelValue)
        })
        // 监听用户输入
        const unWatchInput = watch(inputValue, newInputValue => {
          // 避免粘贴时出现重复的 mdi-，尝试去删除
          if (newInputValue.match(/^mdi-mdi-/)) {
            newInputValue = newInputValue.replace(/^mdi-/, '')
          }
          const newModelValue = encodeModelValue(iconType.value, newInputValue)
          applyBookmarkIcon(newModelValue)
          context.emit('update:modelValue', newModelValue)
        })
        // 标记解除监听回调
        unWatchUserIntractive = () => {
          unWatchIconType()
          unWatchInput()
        }
      }
      // 解除用户交互操作行为监听
      let unWatchUserIntractive = () => {
        // nothind
      }
      // 监听父组件传入的数据变动
      watch(
        () => props.modelValue,
        (newValue: BookmarkIcon) => {
          // 解除用户操作监听
          unWatchUserIntractive()
          // 更新编辑器数据
          applyBookmarkIcon(newValue)
          // 创建用户操作监听
          watchUserIntractive()
        },
        {
          immediate: true,
        }
      )
      return {
        iconType,
        iconTypeLabel,
        iconTypeConfigList,
        inputValue,
        openMdiHelp() {
          window.open('https://pictogrammers.github.io/@mdi/font/2.0.46/', 'material-help')
        },
      }
    },
  }
  </script>
  